package com.ruoyi.quartz.task;

import com.ruoyi.bizsys.service.IAppUserService;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.ObjectUtil;
import com.ruoyi.common.utils.StringRandomUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 邀请码定时任务
 */
@Slf4j
@Component("inviteCodeTask")
public class InviteCodeTask {

    private static final int POOL_THRESHOLD = 50000;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IAppUserService appUserService;


    /**
     * 队列生产者
     */
    public void queueProducer() {
        log.info("InviteCodeTask.queueProducer开始执行");
        Long listSize = redisCache.listSize(RedisCache.INVITE_CODE_QUEUE);
        //存量是否充足
        if (listSize >= POOL_THRESHOLD) {
            log.info("存量充足：{}", listSize);
            return;
        }
        //redis反查
        Set<String> inviteCodeList = checkBackRedis(listSize);
        //批量反查库
        inviteCodeList = checkBackDB(inviteCodeList);
        //头部插入
        redisCache.rightPushAll(RedisCache.INVITE_CODE_QUEUE, inviteCodeList);
        log.info("InviteCodeTask.queueProducer结束执行");
    }

    private Set<String> checkBackRedis(Long listSize) {
        List<String> listAll = redisCache.listRange(RedisCache.INVITE_CODE_QUEUE, 0, -1);
        Set<String> inviteCodeList = new HashSet<>();
        //生成邀请码
        for (int i = 0; i < POOL_THRESHOLD - listSize; i++) {
            String newInviteCode = StringRandomUtils.genRandomNum();
            //不在队列、不在用户表
            if (!listAll.contains(newInviteCode)) {
                inviteCodeList.add(newInviteCode);
            }
        }
        return inviteCodeList;
    }

    private Set<String> checkBackDB(Set<String> inviteCodeSet) {
        //每次一千查询
        int size = (inviteCodeSet.size() / 1000) + 1;
        List<String> inviteCodeList = inviteCodeSet.stream().collect(Collectors.toList());
        List<String> dbInviteList = getDBInviteList(size, inviteCodeList);
        return inviteCodeSet.stream().filter(e -> !dbInviteList.contains(e)).collect(Collectors.toSet());
    }

    private List<String> getDBInviteList(int size, List<String> inviteCodeList) {
        List<List<String>> lists = ObjectUtil.averageAssign(inviteCodeList, size);
        List<String> dbInviteList = new ArrayList<>();
        lists.forEach(e -> {
            //已存在的邀请码
            List<String> inviteList = appUserService.getInviteList(e);
            dbInviteList.addAll(inviteList);
        });
        return dbInviteList;
    }

}
